构造edid内核参数 创建虚拟显示器
·
内核级虚拟显示器(推荐!无需硬件,永久生效)
- 选择一个没有物理显示器的接口(逻辑接口)
- 使用 drm_kms_helper.edid_firmware + 自定义 EDID
for p in /sys/class/drm/*/status; do con=${p%/status}; echo -n "${con#*/card?-}: "; cat $p; done
生成一个标准 EDID(例如 1920x1080)
# 安装 edid-decode(Debian/Ubuntu)
sudo apt install edid-decode
# 创建 1920x1080 EDID 文件(标准 60Hz)
cat > custom-edid.bin <<'EOF'
00ffffffffffff004c2dd707ffffffffff
141a0104a51e177802ee95a3544c9926
0f5054bfef80714f81c0810081809500
a9c0b300950f023a801871382d40582c
4500dd0c1100001e000000ff004c6170
746f702d303030300a20000000fc0044
656c6c205532343139480a20000000fd
00184c1e5111000a2020202020202020
000000ff004c6170746f702d30303030
0a200088
EOF
# 转为二进制(上述已是 hexdump -C 格式,需 decode)
xxd -r -p > edid.bin <<'EOF'
00ffffffffffff004c2dd707ffffffffff141a0104a51e177802ee95a3544c99260f5054bfef80714f81c0810081809500a9c0b300950f023a801871382d40582c4500dd0c1100001e000000ff004c6170746f702d303030300a20000000fc0044656c6c205532343139480a20000000fd00184c1e5111000a2020202020202020000000ff004c6170746f702d303030300a200088
EOF
这是一个标准 Dell U2419H 的 EDID(1920x1080@60Hz),你可用在线工具生成任意分辨率
复制到固件目录
sudo mkdir -p /lib/firmware/edid/
sudo cp edid.bin /lib/firmware/edid/virtual-edid.bin
# 更新 initramfs(Ubuntu/Debian)
sudo update-initramfs -u
# CentOS/RHEL/Fedora
sudo dracut --force
添加内核启动参数(永久生效)
# 编辑 GRUB 配置
sudo nano /etc/default/grub
RUB_CMDLINE_LINUX="... drm_kms_helper.edid_firmware=edid/virtual-edid.bin video=Virtual-1:1920x1080@60"
# 更新 GRUB
sudo update-grub # Debian/Ubuntu
sudo grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL
直接使用dp物理显示器的edid
sudo cat /sys/class/drm/card0-DP-1/edid > /tmp/dp-edid.bin
# 验证内容(应看到显示器型号)
edid-decode /tmp/dp-edid.bin | grep -E "Manufacturer|Model|Name"
sudo mkdir -p /lib/firmware/edid/
# 复制 EDID(命名为 hdmi-edid.bin,清晰表明用途)
sudo cp /tmp/dp-edid.bin /lib/firmware/edid/hdmi-edid.bin
# 更新 initramfs(确保开机加载)
sudo update-initramfs -u # Debian/Ubuntu
sudo dracut --force # RHEL/Fedora
# 编辑 GRUB
sudo nano /etc/default/grub
GRUB_CMDLINE_LINUX="... drm_kms_helper.edid_firmware=HDMI-A-1:edid/hdmi-edid.bin video=HDMI-A-1:1920x1080@60"
# drm.edid_firmware=HDMI-A-1:edid/HDMI-A-1-dp-edid.bin,HDMI-A-2:edid/HDMI-A-1-dp-edid.bin
# HDMI-A-1:目标连接器名(必须与 /sys/class/drm/ 下的名称一致)
# edid/hdmi-edid.bin:相对于 /lib/firmware/ 的路径
# 💡 你有两个 HDMI(HDMI-A-1, HDMI-A-2),选一个未使用的(如 HDMI-A-2)避免冲突
sudo update-grub
dmesg | grep -E "edid|drm_kms_helper|HDMI-A-2"
lsinitramfs /boot/initrd.img-$(uname -r) | grep hdmi-edid.bin || true
sudo update-initramfs -u -k all
sudo update-initramfs -u -k $(uname -r)
# !!!!! 5.12 以上的内核,参数已经变为了drm.edid_firmware
drm.edid_firmware=HDMI-A-2:edid/hdmi-edid.bin video=HDMI-A-2:2560x1440@120e
排查为什么分辨率达不到edid中的配置
# 安装工具
sudo apt install libdrm-tests
# 列出所有 connector 及 mode
sudo modetest -M i915 | grep -A 20 "HDMI-A-2"
# 你的 EDID 中 DTD 未设 preferred bit → GNOME 可能忽略它。
git clone https://github.com/akatrevorjay/edid-generator
cd edid-generator
# 关键:加 --preferred 和 --cvt-rb
./edid-generator.py \
--name "VIRT-2K" \
--width 2560 --height 1440 --refresh 120 \
--timing "2560 2608 2640 2720 1440 1443 1448 1545 +hsync -vsync" \
--cvt-rb \ # 使用 reduced blanking(更省带宽)
--preferred \ # 设为 preferred timing!
--output /lib/firmware/edid/hdmi-edid.bin
sudo update-initramfs -u
# --preferred 让 DRM/GNOME 优先选用该 mode
# --cvt-rb 降低 pixel clock(从 497.75 → ~399 MHz),提高兼容性
fireware 没有被打包金initrd中
sudo tee /etc/initramfs-tools/hooks/zzz_edid_inject <<'EOF'
#!/bin/sh
PREREQ=""
prereqs() { echo "$PREREQ"; }
case "$1" in
prereqs) prereqs; exit 0 ;;
esac
. /usr/share/initramfs-tools/hook-functions
# 创建 firmware 目录(initramfs 中路径是 lib/firmware/...)
mkdir -p "${DESTDIR}/lib/firmware/edid"
# 复制文件(必须用 copy_file,不是 cp!)
copy_file /lib/firmware/edid/hdmi-edid.bin /lib/firmware/edid/hdmi-edid.bin
EOF
# 赋予执行权限(必须!)
sudo chmod +x /etc/initramfs-tools/hooks/zzz_edid_inject
sudo update-initramfs -c -k $(uname -r)
lsinitramfs /boot/initrd.img-$(uname -r) | grep -i 'edid/hdmi-edid'
# 手动解压验证
mkdir /tmp/initrd && cd /tmp/initrd
zcat /boot/initrd.img-$(uname -r) | cpio -id 2>/dev/null
find . -name "*hdmi-edid*" -type f
edid_firmware 和video 参数含义
这两个内核参数是独立的,并且用于不同的目的,但都与显示器的配置有关。
- drm_kms_helper.edid_firmware=...
- 欺骗内核:强制加载一个特定的 EDID 文件来定义显示器的功能(如支持的分辨率、色彩空间等)。
- 独立于 video 参数。用于模拟硬件报告的功能。
- 解决显示器 EDID 报告错误、模拟 4K 分辨率或模拟特定显示器功能。
- video=...
- 强制输出:强制激活一个特定的连接器(Connector)并设置其模式(分辨率和刷新率)。
- 独立于 edid_firmware 参数。用于强制使能输出。
- 解决无头(headless)系统无法识别显示器、强制启用休眠后未恢复的接口。
- 它们是相互独立的。您可以单独使用其中一个,也可以同时使用。
- 如果您只是想启动一个虚拟显示器: 仅使用 video=HDMI-A-2:1920x1080@60e 通常就足够了。
- 如果您需要更复杂的显示器功能模拟: 您可能需要同时使用这两个参数。
参数名称
-
这里的 HDMI-A-2 必须与您的 Linux 系统在 /sys/class/drm/*/status 中报告的逻辑接口名称完全一致。
-
逻辑名称 (HDMI-A-1, HDMI-A-2) 不一定对应您的显卡背后的物理插槽编号。它只是 GPU 驱动程序报告的内部通道名称。 民用主板一般不会将所有的逻辑接口都配置物理接口(成本考虑)
-
如果目标是模拟一个虚拟显示器(无头模式): 您应该选择一个 当前没有物理显示器连接 且 状态显示为 disconnected 的接口名称(例如 HDMI-A-2)。这样,内核就会认为您有一个显示器连接在 HDMI-A-2 上,并使用您指定的参数。
-
如果目标是修复一个已连接的显示器的问题: 您应该选择该显示器实际连接的、状态显示为 connected 的那个接口名称(例如 HDMI-A-1)。
-
video=HDMI-A-2:1920x1080@60e
- video=: 告诉内核加载视频模式。
- HDMI-A-2: 目标连接器名称。
- 1920x1080: 要设置的分辨率。
- @60: 要设置的刷新率(60 Hz)。
- e (可选): 重要,表示 强制启用 (enable)。当连接器处于 disconnected 状态时,添加 e 可以强制驱动程序尝试启用它,非常适合构造虚拟显示器。
-
drm_kms_helper.edid_firmware=HDMI-A-2:edid/1920x1080.bin
- drm_kms_helper.edid_firmware=: 告诉内核覆盖 EDID 报告。
- HDMI-A-2: 目标连接器名称。
- edid/1920x1080.bin: EDID 文件路径。您需要手动将一个有效的 EDID 二进制文件放置在 /lib/firmware/edid/ 目录下。例如,您可以从一台工作正常的显示器上获取 EDID,或者使用工具生成一个。
依赖关系
- drm_kms_helper.edid_firmware=HDMI-A-2:edid/xxx.bin
- 阶段1:连接器探测, 将指定 EDID,注入到连接器的 edid 文件中,使内核认为“此接口接了显示器”
- ❌ 不依赖 video= ;即使没 video=,/sys/class/drm/card0-HDMI-A-2/status 也会变成 connected
- video=HDMI-A-2:1920x1080@60
- 阶段2:模式设置,强制激活该连接器的特定显示模式,(即使 EDID 中没有此模式)
- ✅ 依赖连接器 connected(否则无效)
自定义 EDID 生成
方法:用 cvt + parse-edid + edid-generator
cvt 2540 1440 120
# 输出类似:
# Modeline "2540x1440_120.00" 852.75 2540 2728 2992 3472 1440 1443 1453 1538 -hsync +vsync
用工具生成 EDID: 推荐工具:https://github.com/akatrevorjay/edid-generator
git clone https://github.com/akatrevorjay/edid-generator
cd edid-generator
./edid-generator.py --name "VIRT-MON" --width 2540 --height 1440 --refresh 120 --timing "2540 2728 2992 3472 1440 1443 1453 1538 +hsync +vsync" --output hdmi-edid.bin
# 验证:
edid-decode hdmi-edid.bin | grep -A5 "Detailed"